#include "cps.h"

// CPS Scroll2 with Row scroll - Draw
static int nKnowBlank=-1;	// The tile we know is blank
static int nFirstY, nLastY;
static int bVCare;

// Find tile address
static inline unsigned short *FindTile(int fx,int fy)
{
	int p;
	unsigned short *pst;
	p=((fy & 0x30) << 8) | ((fx & 0x3f) << 6) | ((fy & 0x0f) << 2);
	pst=(unsigned short *)(CpsrBase + p);
	return pst;
}

// Draw a tile line without Row Shift
static void Cps1TileLine(int y, int sx)
{
	int x, ix, iy, sy;

	bVCare=0;
	if (y < 0 || y >= 13)	// Take care on the edges
		bVCare = 1;

	ix = (sx >> 4) + 1;
	sx = 0x10 - (sx & 0x0f);
	sy = 0x10 - (nCpsrScrY & 0x0f);
	iy = (nCpsrScrY >> 4) + 1;
	nCpstY = sy + (y << 4);

	for (x = -1; x < 24; x++)
	{
		int t,a;
		unsigned short *pst;

		// Don't need to clip except around the border
		if (bVCare || x < 0 || x >= 23)
			nCpstType = CTT_16X16 | CTT_CARE;
		else
			nCpstType = CTT_16X16;

		pst = FindTile(ix + x, iy + y);
		t = pst[0];

		if (Scroll2TileMask) t &= Scroll2TileMask;

		t = GfxRomBankMapper(GFXTYPE_SCROLL2, t);
		if (t == -1) continue;

		t = (t << 7) + nCpsGfxScroll[2]; // Get real tile address and add offset to scroll tiles

		if (t == nKnowBlank)	// Don't draw: we know it's blank
			continue;
		a = pst[1];

		CpstSetPal(0x40 | (a & 0x1f));
		nCpstX = sx + (x << 4);
		nCpstTile = t;
		nCpstFlip = (a >> 5) & 3;

		if(nBgHi) {
			CpstPmsk=*(unsigned short *)(CpsSaveReg[0] + MaskAddr[(a & 0x180) >> 7]);
		}

		if(CpstOneDoX[nBgHi]()) {
			nKnowBlank=t;
		}
	}
}

static void Cps2TileLine(int y,int sx)
{
	int x, ix, iy, sy;

	ix = (sx >> 4) + 1;
	sx = 0x10 - (sx & 0x0f);
	sy = 0x10 - (nCpsrScrY & 0x0f);
	iy = (nCpsrScrY >> 4) + 1;
	nCpstY = sy + (y<<4);

	for (x = -1; x < 24; x++)
	{
		int t,a;
		unsigned short *pst;

		// Don't need to clip except around the border
		if (bVCare || x < 0 || x >= 23)
			nCpstType = CTT_16X16 | CTT_CARE;
		else
			nCpstType = CTT_16X16;

		pst = FindTile(ix + x, iy + y);
		t = pst[0];

		t = (t << 7) + nCpsGfxScroll[2]; // Get real tile address and add offset to scroll tiles

		if (t == nKnowBlank)	// Don't draw: we know it's blank
			continue;

		a = pst[1];

		CpstSetPal(0x40 | (a & 0x1f));

		nCpstX = sx + (x << 4);
		nCpstTile = t;
		nCpstFlip = (a >> 5) & 3;

		if(CpstOneDoX[2]()) {
			nKnowBlank=t;
		}
	}
}

// Draw a tile line with Row Shift
static void Cps1TileLineRows(int y,struct CpsrLineInfo *pli)
{
	int sy,iy,x;
	int nTileCount;
	int nLimLeft,nLimRight;

	bVCare=0;
	if (y<0 || y>=14-1) bVCare=1; // Take care on the edges

	nTileCount=pli->nTileEnd-pli->nTileStart;

	sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
	nCpstY=sy+(y<<4);
	CpstRowShift=pli->Rows;

	// If these rowshift limits go off the edges, we should take
	// care drawing the tile.
	nLimLeft =pli->nMaxLeft;
	nLimRight=pli->nMaxRight;
	for (x=0; x<nTileCount; x++, nLimLeft+=16, nLimRight+=16)
	{
		unsigned short *pst; int t,a; int tx; int bCare;
		tx=pli->nTileStart+x;

		// See if we have to clip vertically anyway
		bCare=bVCare;
		if (bCare==0) // If we don't...
		{
			// Check screen limits of this tile
			if (nLimLeft <      0) bCare=1; // Will cross left egde
			if (nLimRight> 384-16) bCare=1; // Will cross right edge
		}
		if (bCare) nCpstType=CTT_16X16 | CTT_ROWS | CTT_CARE;
		else       nCpstType=CTT_16X16 | CTT_ROWS;

		pst=FindTile(tx,iy+y);
		t=pst[0];

		if (Scroll2TileMask) t &= Scroll2TileMask;

		t = GfxRomBankMapper(GFXTYPE_SCROLL2, t);
		if (t == -1) continue;

		t<<=7; // Get real tile address
		t+=nCpsGfxScroll[2]; // add on offset to scroll tiles

		if (t==nKnowBlank) continue; // Don't draw: we know it's blank
		a=pst[1];

		CpstSetPal(0x40 | (a&0x1f));

		nCpstX=x<<4; nCpstTile=t; nCpstFlip=(a>>5)&3;

		if (nBgHi) {
			CpstPmsk = *(unsigned short*)(CpsSaveReg[0] + MaskAddr[(a & 0x180) >> 7]);
		}

		if(CpstOneDoX[nBgHi]()) nKnowBlank=t;
	}
}

static void Cps2TileLineRows(int y,struct CpsrLineInfo *pli)
{
	int sy,iy,x;
	int nTileCount;
	int nLimLeft,nLimRight;

	nTileCount=pli->nTileEnd-pli->nTileStart;

	sy=16-(nCpsrScrY&15); iy=(nCpsrScrY>>4)+1;
	nCpstY=sy+(y<<4);
	CpstRowShift=pli->Rows;

	// If these rowshift limits go off the edges, we should take
	// care drawing the tile.
	nLimLeft =pli->nMaxLeft;
	nLimRight=pli->nMaxRight;
	for (x=0; x<nTileCount; x++, nLimLeft+=16, nLimRight+=16)
	{
		unsigned short *pst; int t,a; int tx; int bCare;
		tx=pli->nTileStart+x;

		// See if we have to clip vertically anyway
		bCare=bVCare;
		if (bCare==0) // If we don't...
		{
			// Check screen limits of this tile
			if (nLimLeft <      0) bCare=1; // Will cross left egde
			if (nLimRight> 384-16) bCare=1; // Will cross right edge
		}
		if (bCare) nCpstType=CTT_16X16 | CTT_ROWS | CTT_CARE;
		else       nCpstType=CTT_16X16 | CTT_ROWS;

		pst=FindTile(tx,iy+y);
		t=pst[0];
		t<<=7; // Get real tile address
		t+=nCpsGfxScroll[2]; // add on offset to scroll tiles

		if (t==nKnowBlank) continue; // Don't draw: we know it's blank
		a=pst[1];

		CpstSetPal(0x40 | (a&0x1f));

		nCpstX=x<<4; nCpstTile=t; nCpstFlip=(a>>5)&3;
		if(CpstOneDoX[2]()) nKnowBlank=t;
	}
}

int Cps1rRender()
{
	int y; struct CpsrLineInfo *pli;
	if (CpsrBase==NULL) return 1;

	nKnowBlank=-1; // We don't know which tile is blank yet

	for (y=-1,pli=CpsrLineInfo; y<14; y++,pli++) {
		if (pli->nWidth==0)
			Cps1TileLine(y,pli->nStart); // no rowscroll needed
		else
			Cps1TileLineRows(y,pli); // row scroll
	}
	return 0;
}

int Cps2rRender()
{
	int y;
	struct CpsrLineInfo *pli;
	if (CpsrBase==NULL) return 1;

	nKnowBlank = -1;					// We don't know which tile is blank yet

	nLastY = (nEndline + (nCpsrScrY & 15)) >> 4;
	nFirstY = (nStartline + (nCpsrScrY & 15)) >> 4;
	for (y = nFirstY - 1, pli = CpsrLineInfo + nFirstY; y < nLastY; y++, pli++) {

		bVCare = ((y << 4) < nStartline) | (((y << 4) + 16) >= nEndline);

		if (pli->nWidth==0) {
			Cps2TileLine(y,pli->nStart);	// no rowscroll needed
		} else {
			Cps2TileLineRows(y,pli);		// row scroll
		}
	}
	return 0;
}
